package src.view;

import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashMap;

import javax.imageio.ImageIO;

import src.controller.MainViewKeyListener;
import src.event.EventHandler;
import src.event.events.ConsoleUpdateEvent;
import src.event.events.CursorChangeEvent;
import src.event.events.TechUpdateEvent;
import src.model.gameWorld.MapTileConfiguration;

/**
 * <b>Overview</b>
 * The ViewHandler is responsible for what is displayed to the screen.  All Viewports update themselves when an event triggers them, but only the ViewHandler allows the updates to be displayed.  In this way, individual Viewports do not have to keep track of whether they are visible or not.
 *
 * <b>Responsibilities</b>
 * Update the appropriate Viewports as the user performs actions such as changing views or destroying or moving units, etc.
 *
 * <b>Collaborators</b>
 * Every Viewport - Client: each Viewport is updated through the ViewHandler.
 *
 * <b>Implementor</b> - Bruce
 * <b>Tester</b> - Tim
 *
 * @author Bruce
 */
public class ViewHandler implements ComponentListener, MouseListener, KeyListener
{
	private EnumMap<ImageType, BufferedImage> images = new EnumMap<ImageType, BufferedImage>(ImageType.class);

	private Collection<Viewport> ports = new ArrayList<Viewport>();

	private AreaViewport av;

	private ConsoleViewport cv;

	private StructureViewport rv;

	private StatusViewport sv;

	private TechnologyViewport tv;

	private UnitViewport uv;

	private StartupViewport iv;

	private TurnViewport nv;

	private DisplayType display;

	//Key Listeners
	private KeyListener mvkl;

	private KeyListener uokl;

	private KeyListener sokl;

	//Mouse Listeners
	private MouseListener mml;

	private MouseListener uoml;

	private MouseListener soml;

	private MouseListener toml;

	private MouseListener aml;

	public enum DisplayType
	{
		MAIN, UNIT, STRUCTURE, TECHNOLOGY, NEWTURN, STARTUP
	}

	private MapTileConfiguration tileConfig;

	private int tileWidth;
	private int tileHeight;
	private MainWindow mw;

	public ViewHandler(MapTileConfiguration config)
	{
		setupImages();
		mw = new MainWindow();
//		mw.addComponentListener(this);
		mw.addMouseListener(this);
		mw.addKeyListener(this);
		av = new AreaViewport(this, mw, config);
		cv = new ConsoleViewport(this, mw);
		rv = new StructureViewport(this, mw);
		sv = new StatusViewport(this, mw);
		tv = new TechnologyViewport(this, mw);
		uv = new UnitViewport(this, mw);
		iv = new StartupViewport(this, mw);
		nv = new TurnViewport(this, mw);
		MapDataCache c = new MapDataCache(sv, av);

		tileWidth = 50;
		tileHeight = 50;

		av.setTileWidth(tileWidth);
		av.setTileHeight(tileHeight);

		ViewEventHandler.setSelectionListener(new SelectionCacheHandler(c));
		ViewEventHandler.setMapListener(new MapCacheHandler(c));
		ViewEventHandler.setCursorListener(new CursorCacheHandler(c));

		setPorts();

		EventHandler<ConsoleUpdateEvent> cl = new EventHandler<ConsoleUpdateEvent>();
		ViewEventHandler.setConsoleListener(cl);
		cl.regesterListener(cv);

		EventHandler<TechUpdateEvent> tl = new EventHandler<TechUpdateEvent>();
		ViewEventHandler.setTechListener(tl);
		tl.regesterListener(tv);

		lastRefreshTime = System.currentTimeMillis();
	}

	private void setPorts()
	{
		ports.clear();
		ports.add(av);
		ports.add(cv);
		ports.add(rv);
		ports.add(sv);
		ports.add(tv);
		ports.add(uv);
		ports.add(iv);
		ports.add(nv);
	}

	protected BufferedImage getImage(ImageType type)
	{
		return images.get(type);
	}

	public void setDisplayType(MapTileConfiguration type)
	{
		av = new AreaViewport(this, mw, type);
		av.setTileWidth(tileWidth);
		av.setTileHeight(tileHeight);
		MapDataCache c = new MapDataCache(sv, av);
		ViewEventHandler.setSelectionListener(new SelectionCacheHandler(c));
		ViewEventHandler.setMapListener(new MapCacheHandler(c));
		ViewEventHandler.setCursorListener(new CursorCacheHandler(c));
		setPorts();
	}

	protected enum ImageType
	{
		SHIP, PARCHMENT, WOOD, SELECTION, WHITE, BLACK, RED, GREEN, BLUE, PINK, YELLOW, ORANGE, BUTTON,
		PANEL, GOLD, RUM, LUMBER, SCROLLBAR, ARROWUP, ARROWDOWN, POINT, PAPER, UOS, SOS, HEX,
		SAND, WATER, CORSAIR, B_UNIT, B_STRUCT, B_TECH
	}

	private void registerImage(String s, ImageType type)
	{
		try {
		BufferedImage good, image;
		GraphicsConfiguration compatible = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();

		image = ImageIO.read(new File(s));
		good = compatible.createCompatibleImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
		good.getGraphics().drawImage(image, 0, 0, null);
		images.put(type, good);
		}catch(Exception e) {}
	}

	private void setupImages()
	{
			registerImage("images/parchment.png", ImageType.PARCHMENT);
			registerImage("images/wood.png", ImageType.WOOD);
			registerImage("images/panel.png", ImageType.PANEL);
			registerImage("images/paper.png", ImageType.PAPER);
			registerImage("images/ship.png", ImageType.SHIP);

			registerImage("images/sos.png", ImageType.SOS);
			registerImage("images/uos.png", ImageType.UOS);

			registerImage("images/colors/selection.png", ImageType.SELECTION);
			registerImage("images/colors/white.png", ImageType.WHITE);
			registerImage("images/colors/black.png", ImageType.BLACK);
			registerImage("images/colors/blue.png", ImageType.BLUE);
			registerImage("images/colors/red.png", ImageType.RED);
			registerImage("images/colors/green.png", ImageType.GREEN);
			registerImage("images/colors/yellow.png", ImageType.YELLOW);
			registerImage("images/colors/pink.png", ImageType.PINK);
			registerImage("images/colors/orange.png", ImageType.ORANGE);

			registerImage("images/button/start.png", ImageType.BUTTON);
			registerImage("images/button/hex.png", ImageType.HEX);

			registerImage("images/scrollbar.png", ImageType.SCROLLBAR);
			registerImage("images/barpoint.png", ImageType.POINT);
			registerImage("images/arrowdown.png", ImageType.ARROWDOWN);
			registerImage("images/arrowup.png", ImageType.ARROWUP);

			registerImage("images/resources/gold.png", ImageType.GOLD);
			registerImage("images/resources/rum.png", ImageType.RUM);
			registerImage("images/resources/lumber.png", ImageType.LUMBER);

			registerImage("images/terrain/sand.png", ImageType.SAND);
			registerImage("images/terrain/water.png", ImageType.WATER);

			registerImage("images/sprites/double.png", ImageType.CORSAIR);

			registerImage("images/button/structure.png", ImageType.B_STRUCT);
			registerImage("images/button/tech.png", ImageType.B_TECH);
			registerImage("images/button/unit.png", ImageType.B_UNIT);
	}

	public void setDisplay(DisplayType type)
	{
		display = type;
		refresh();
	}

	public void setMapTileConfiguration(MapTileConfiguration mtc){
		this.tileConfig = mtc;
		av.setMapTileConfiguration(mtc);
	}

	public void componentHidden(ComponentEvent e)
	{}

	public void componentMoved(ComponentEvent e)
	{}

	private long lastRefreshTime;

	public void componentResized(ComponentEvent e)
	{
		refresh();
	}

	public void componentShown(ComponentEvent e)
	{}

	/**
	 * Refreshes the current display.
	 */
	private void refresh()
	{
		lastRefreshTime = System.currentTimeMillis();
		for(Viewport vp : ports)
			vp.refresh(display);
	}

	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
	 */
	public void mouseClicked(MouseEvent e)
	{
		Point p = e.getPoint();

		switch(display)
		{
			case MAIN:
			{
				for(Viewport port : ports)
				{
					port.clicked(display, p);
					((MainViewKeyListener)mvkl).getGC().updateCursor(av.getCursorPos());
				}
				aml.mouseClicked(new MouseEvent(mw, e.getID(), e.getWhen(), e.getModifiers(), av.getCursorPos().X(), av.getCursorPos().Y(), 0, 0, 1, e.isPopupTrigger(), e.getButton()));

				break;
			}
			case NEWTURN:
			{
				setDisplay(DisplayType.MAIN);
				break;
			}
			case STRUCTURE:
			{
				break;
			}
			case TECHNOLOGY:
			{
				break;
			}
			case UNIT:
			{
				break;
			}
			case STARTUP:
			{
				iv.click(p);
				break;
			}
		}
		// TODO Stub
	}

	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
	 */
	public void mouseEntered(MouseEvent e)
	{
		// TODO Stub
	}

	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
	 */
	public void mouseExited(MouseEvent e)
	{
		// TODO Stub
	}

	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
	 */
	public void mousePressed(MouseEvent e)
	{
		// TODO Stub
	}

	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
	 */
	public void mouseReleased(MouseEvent e)
	{
		// TODO Stub
	}

	public void registerMainViewKeyListener(KeyListener listener)
	{
		mvkl = listener;
	}

	public void registerUnitOverviewKeyListener(KeyListener listener)
	{
		uokl = listener;
	}

	public void registerStructureOverviewKeyListener(KeyListener listener)
	{
		sokl = listener;
	}

	public void registerMapMouseListener(MouseListener listener)
	{
		mml = listener;
	}

	public void registerAbilityMouseListener(MouseListener listener)
	{
		aml = listener;
	}

	public void registerUnitOverviewMouseListener(MouseListener listener)
	{
		uoml = listener;
	}

	public void registerStructureOverviewMouseListener(MouseListener listener)
	{
		soml = listener;
	}

	public void registerTechnologyOverviewMouseListener(MouseListener listener)
	{
		toml = listener;
	}

	/* (non-Javadoc)
	 * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
	 */
	public void keyPressed(KeyEvent e)
	{
		if(display == DisplayType.STARTUP)
			iv.keyTyped(e);
		else if(display == DisplayType.MAIN)
			if(e.getKeyChar() == ' ')
				setDisplay(DisplayType.NEWTURN);
	}

	/* (non-Javadoc)
	 * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
	 */
	public void keyReleased(KeyEvent e)
	{}

	/* (non-Javadoc)
	 * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
	 */
	public void keyTyped(KeyEvent e)
	{
		switch(display)
		{
			case MAIN:
			{
				mvkl.keyTyped(e);
				break;
			}
			case STRUCTURE:
			{
				sokl.keyTyped(e);
				setDisplay(DisplayType.MAIN);
				break;
			}
			case UNIT:
			{
				uokl.keyTyped(e);
				setDisplay(DisplayType.MAIN);
				break;
			}
			case TECHNOLOGY:
			{
				setDisplay(DisplayType.MAIN);
				break;
			}
			case NEWTURN:
			{
//				setDisplay(DisplayType.MAIN);
				break;
			}
		}
	}
}